package com.example.huadu_server.appointment.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.example.huadu_server.appointment.dto.AppointmentAuditDTO;
import com.example.huadu_server.appointment.dto.AppointmentDTO;
import com.example.huadu_server.appointment.dto.ChangeDateDTO;
import com.example.huadu_server.appointment.entity.Appointment;
import com.example.huadu_server.appointment.mapper.AppointmentMapper;
import com.example.huadu_server.appointment.service.AppointmentService;
import com.example.huadu_server.config.Response;
import com.example.huadu_server.house.entity.House;
import com.example.huadu_server.house.mapper.HouseImageMapper;
import com.example.huadu_server.house.mapper.HouseMapper;
import com.example.huadu_server.landlord.entity.Landlord;
import com.example.huadu_server.landlord.entity.LandlordSchedule;
import com.example.huadu_server.landlord.mapper.LandlordMapper;
import com.example.huadu_server.landlord.mapper.LandlordScheduleMapper;
import com.example.huadu_server.user.entity.User;
import com.example.huadu_server.user.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;

import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;

@Service
public class AppointmentServiceImpl implements AppointmentService {

    @Autowired
    private AppointmentMapper appointmentMapper;

    @Autowired
    private HouseMapper houseMapper;

    @Autowired
    private LandlordMapper landlordMapper;

    @Autowired
    private HouseImageMapper houseImageMapper;

    @Autowired
    private LandlordScheduleMapper landlordScheduleMapper;


    @Autowired
    private UserMapper userMapper;

    @Autowired
    private JavaMailSender mailSender;

    @Value("${spring.mail.username}")  // 从配置文件中注入发件人邮箱
    private String senderEmail;

    /**
     * 预约房源
     * @param appointmentDTO
     * @return
     */
    // 预约房源接口修改后使用档期记录中的时间
    @Override
    @Transactional
    public Response<String> reserveHouse(AppointmentDTO appointmentDTO) {
        // 1. 校验房源是否存在
        House house = houseMapper.getHouseById(appointmentDTO.getHouseId());
        if (house == null) {
            return new Response<>(404, "房源不存在", null);
        }

        // 2. 校验档期是否存在
        LandlordSchedule schedule = landlordScheduleMapper.selectById(appointmentDTO.getScheduleId());
        if (schedule == null) {
            return new Response<>(404, "档期不存在", null);
        }

        // 3. 校验档期状态
        if ("forbid".equals(schedule.getStatus())) {
            return new Response<>(500, "该档期已被房东设置为不可预约", null);
        }

        if ("expired".equals(schedule.getStatus())) {
            return new Response<>(500, "该档期已经过期，无法进行预约", null);
        }

        if ("booked".equals(schedule.getStatus())) {
            return new Response<>(500, "该档期已被预约，请选择其他档期", null);
        }

        // 4. 校验预约时间是否合法（不能是过去的时间）
        LocalDate localDate = schedule.getScheduleDate().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
        LocalTime localTime = schedule.getStartTime().toLocalTime();
        LocalDateTime localDateTime = LocalDateTime.of(localDate, localTime);
        Timestamp appointmentTime = Timestamp.valueOf(localDateTime);

        if (appointmentTime.before(new Date())) {
            return new Response<>(500, "预约时间已过，无法进行预约", null);
        }

        // 5. 获取房东ID
        Integer landlordId = house.getLandlordId();
        if (landlordId == null) {
            return new Response<>(500, "房源数据错误，无法获取房东信息", null);
        }

        // 6. 创建预约对象
        Appointment appointment = new Appointment();
        appointment.setUserId(appointmentDTO.getUserId());
        appointment.setLandlordId(landlordId);
        appointment.setHouseId(appointmentDTO.getHouseId());
        appointment.setScheduleId(appointmentDTO.getScheduleId());
        appointment.setAppointmentDate(new Date(appointmentTime.getTime()));
        appointment.setAppointmentStatus("pending");
        appointment.setRemarks("待看房");

        // 7. 插入预约记录
        int result = appointmentMapper.insert(appointment);
        if (result > 0) {
            // 8. 更新档期状态为 'booked'
            schedule.setStatus("booked");
            landlordScheduleMapper.updateById(schedule);

            // 9. 发送邮件通知房东
            Landlord landlord = landlordMapper.selectById(landlordId);
            if (landlord != null && landlord.getEmail() != null) {
                sendEmailToLandlord(landlord.getEmail());
            }

            return new Response<>(200, "预约成功，等待房东确认", null);
        } else {
            return new Response<>(500, "预约失败，请稍后重试", null);
        }
    }




    /**
     * 发送邮件通知房东
     */
    private void sendEmailToLandlord(String landlordEmail) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(senderEmail);
        message.setTo(landlordEmail);
        message.setSubject("房源预约通知");
        message.setText("您好，您的房源有新的预约，请及时查看" );

        try {
            mailSender.send(message);
        } catch (Exception e) {
            System.out.println("邮件发送失败：" + e.getMessage());
        }
    }

    /**
     * 根据用户ID获取预约记录
     * @param userId
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public Response<Map<String, Object>> getAppointmentsByUserId(int userId, int pageNo, int pageSize) {
        if (pageNo < 1) {
            pageNo = 1;
        }
        int offset = (pageNo - 1) * pageSize;

        // 查询预约总数
        LambdaQueryWrapper<Appointment> countWrapper = new LambdaQueryWrapper<>();
        countWrapper.eq(Appointment::getUserId, userId);
        int total = Math.toIntExact(appointmentMapper.selectCount(countWrapper));

        // 查询分页数据（按预约时间降序排列）
        LambdaQueryWrapper<Appointment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Appointment::getUserId, userId)
                .orderByDesc(Appointment::getTime)
                .last("LIMIT " + offset + ", " + pageSize);
        List<Appointment> appointments = appointmentMapper.selectList(queryWrapper);

        // 获取当前时间
        LocalDateTime currentTime = LocalDateTime.now();

        // 遍历预约数据，检查预约时间，更新状态
        for (Appointment appt : appointments) {
            if (appt.getAppointmentDate() != null) {
                // 将预约时间转换为 LocalDateTime 如果它不是 LocalDateTime
                LocalDateTime appointmentDate = appt.getAppointmentDate().toInstant()
                        .atZone(ZoneId.systemDefault()).toLocalDateTime();

                // 比较预约时间是否早于当前时间
                if (appointmentDate.isBefore(currentTime)) {
                    // 更新状态为 expired
                    appt.setAppointmentStatus("expired");
                    appt.setRemarks("已过期");
                    appointmentMapper.updateById(appt);  // 更新数据库中的状态
                }
            }
        }

        // 整合房源和房东信息到一个 Map 中返回给前端
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (Appointment appt : appointments) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", appt.getId());
            map.put("houseId", appt.getHouseId());
            map.put("scheduleId", appt.getScheduleId());
            map.put("appointmentDate", appt.getAppointmentDate());
            map.put("appointmentStatus", appt.getAppointmentStatus());
            map.put("remarks", appt.getRemarks());

            // 获取房源信息：查询房源实体和图片（取第一张）
            House house = houseMapper.getHouseById(appt.getHouseId());
            if (house != null) {
                List<String> images = houseImageMapper.getImagesByHouseId(house.getId());
                map.put("houseImage", (images != null && !images.isEmpty()) ? images.get(0) : null);
                map.put("houseType", house.getHouseType());
            }

            // 获取房东信息
            Landlord landlord = landlordMapper.getLandlordById(appt.getLandlordId());
            if (landlord != null) {
                map.put("landlordName", landlord.getUsername());
                map.put("landlordId", landlord.getId());
                map.put("landlordPhone", landlord.getPhone());
            }
            resultList.add(map);
        }

        // 构造返回结果
        Map<String, Object> response = new HashMap<>();
        response.put("total", total);
        response.put("appointments", resultList);
        response.put("pageNo", pageNo);
        response.put("pageSize", pageSize);

        return new Response<>(200, "查询成功", response);
    }

    /**
     * 获取房东的预约列表（包括所有状态）
     * @param landlordId
     * @param status
     * @param pageNo
     * @param pageSize
     * @return
     */
    @Override
    public Response<Map<String, Object>> getAppointmentsByLandlordId(int landlordId, String status, int pageNo, int pageSize) {
        if (pageNo < 1) {
            pageNo = 1;
        }
        int offset = (pageNo - 1) * pageSize;

        // 查询总记录数
        LambdaQueryWrapper<Appointment> countWrapper = new LambdaQueryWrapper<>();
        countWrapper.eq(Appointment::getLandlordId, landlordId);
        int total = Math.toIntExact(appointmentMapper.selectCount(countWrapper));

        // 查询分页数据
        LambdaQueryWrapper<Appointment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Appointment::getLandlordId, landlordId);
        if (status != null && !status.trim().isEmpty()) {
            queryWrapper.eq(Appointment::getAppointmentStatus, status);
        }

        queryWrapper.orderByDesc(Appointment::getAppointmentDate)
                .last("LIMIT " + offset + ", " + pageSize);
        List<Appointment> appointments = appointmentMapper.selectList(queryWrapper);

        // 获取当前时间
        LocalDateTime currentTime = LocalDateTime.now();

        // 遍历预约数据，检查预约时间，更新状态
        for (Appointment appt : appointments) {
            if (appt.getAppointmentDate() != null) {
                // 将预约时间转换为 LocalDateTime 如果它不是 LocalDateTime
                LocalDateTime appointmentDate = appt.getAppointmentDate().toInstant()
                        .atZone(ZoneId.systemDefault()).toLocalDateTime();

                // 比较预约时间是否早于当前时间
                if (appointmentDate.isBefore(currentTime)) {
                    // 更新状态为 expired
                    appt.setAppointmentStatus("expired");
                    appt.setRemarks("已过期");
                    appointmentMapper.updateById(appt);  // 更新数据库中的状态
                }
            }
        }

        // 整合房源和用户信息到一个 Map 中返回给前端
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (Appointment appt : appointments) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", appt.getId());
            map.put("houseId", appt.getHouseId());
            map.put("scheduleId", appt.getScheduleId());
            map.put("appointmentDate", appt.getAppointmentDate());
            map.put("appointmentStatus", appt.getAppointmentStatus());
            map.put("remarks", appt.getRemarks());

            // 获取房源信息：查询房源实体和图片（取第一张）
            House house = houseMapper.getHouseById(appt.getHouseId());
            if (house != null) {
                List<String> images = houseImageMapper.getImagesByHouseId(house.getId());
                map.put("houseImage", (images != null && !images.isEmpty()) ? images.get(0) : null);
                map.put("houseType", house.getHouseType());
            }

            // 获取用户信息：用户名称和联系电话
            User user = userMapper.selectById(appt.getUserId());
            if (user != null) {
                map.put("userName", user.getUsername());
                map.put("userId", user.getId());
                map.put("userPhone", user.getPhone());
            }

            resultList.add(map);
        }

        // 构造返回结果
        Map<String, Object> response = new HashMap<>();
        response.put("total", total);
        response.put("appointments", resultList);
        response.put("pageNo", pageNo);
        response.put("pageSize", pageSize);

        return new Response<>(200, "查询成功", response);
    }


    /**
     * 房东审核预约
     */
    @Override
    @Transactional
    public Response<String> auditAppointment(int currentLandlordId, AppointmentAuditDTO appointmentAuditDTO) {
        // 1. 查询预约是否存在
        Appointment appointment = appointmentMapper.selectById(appointmentAuditDTO.getAppointmentId());
        if (appointment == null) {
            return new Response<>(404, "预约不存在", null);
        }
        // 2. 只能审核 pending 状态的预约
        if (!"pending".equals(appointment.getAppointmentStatus())) {
            return new Response<>(400, "该预约已审核，不能重复操作", null);
        }
        // 3. 校验当前登录房东是否为该预约对应的房东
        if (appointment.getLandlordId() == null || currentLandlordId != appointment.getLandlordId()) {
            return new Response<>(403, "您无权审核该预约", null);
        }
        // 4. 如果审核结果为拒绝，则必须填写拒绝理由
        if ("rejected".equals(appointmentAuditDTO.getAppointmentStatus()) &&
                (appointmentAuditDTO.getRemarks() == null || appointmentAuditDTO.getRemarks().trim().isEmpty())) {
            return new Response<>(400, "拒绝预约时必须填写拒绝理由", null);
        }
        // 5. 更新预约状态和备注
        appointment.setAppointmentStatus(appointmentAuditDTO.getAppointmentStatus());
        appointment.setRemarks(appointmentAuditDTO.getRemarks());
        int updateCount = appointmentMapper.updateById(appointment);
        if (updateCount <= 0) {
            return new Response<>(500, "审核失败", null);
        }
        // 6. 发送邮件通知用户审核结果
        User user = userMapper.selectById(appointment.getUserId());
        if (user != null && user.getEmail() != null) {
            sendEmailToUser(user.getEmail(), appointmentAuditDTO.getAppointmentStatus(), appointmentAuditDTO.getRemarks());
        }
        return new Response<>(200, "审核成功", null);
    }



    /**
     * 发送邮件通知用户审核结果
     */
    private void sendEmailToUser(String userEmail, String status, String remarks) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(senderEmail);  // 你的发件邮箱
        message.setTo(userEmail);
        message.setSubject("房源预约结果");
        String messageText;
        if (status.equals("approved")) {
            messageText = "您的预约已被批准。";
        } else if (status.equals("rejected")) {
            messageText = "您的预约已被拒绝。\n拒绝理由为：" + remarks;
        } else {
            messageText = "您的预约状态未知。";
        }
        message.setText(messageText);
        try {
            mailSender.send(message);
        } catch (Exception e) {
            System.out.println("邮件发送失败：" + e.getMessage());
        }
    }

    /**
     * 变更预约时间接口
     */
    @Override
    @Transactional
    public Response<String> changeAppointmentTime(ChangeDateDTO changeDateDTO) {
        // 1. 查询原档期和新档期
        LandlordSchedule originalSchedule = landlordScheduleMapper.selectById(changeDateDTO.getOriginalScheduleId());
        LandlordSchedule newSchedule = landlordScheduleMapper.selectById(changeDateDTO.getNewScheduleId());

        if (originalSchedule == null || newSchedule == null) {
            return new Response<>(404, "档期不存在", null);
        }

        // 2. 确保原档期为 booked，新的档期为 available
        if ("expired".equals(originalSchedule.getStatus())) {  // 避免空指针的写法
            return new Response<>(400, "原档期已过期，无法变更", null);
        }

        // 3. 更新档期状态
        // 原档期设置为 available
        originalSchedule.setStatus("available");
        landlordScheduleMapper.updateById(originalSchedule);

        // 新档期设置为 booked
        newSchedule.setStatus("booked");
        landlordScheduleMapper.updateById(newSchedule);

        // 4. 更新预约记录中的时间和状态
        //更新预约记录的档期id
        Appointment appointment = appointmentMapper.selectById(changeDateDTO.getId());
        if (appointment == null) {
            return new Response<>(404, "预约记录不存在", null);
        }

        // 更新预约时间和状态
        // 将 Date 转换为 LocalDateTime
        Date date = changeDateDTO.getNewAppointmentDate();
        LocalDateTime newAppointmentDate = date.toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDateTime();
        appointment.setAppointmentDate(Timestamp.valueOf(newAppointmentDate));
        appointment.setScheduleId(changeDateDTO.getNewScheduleId());  // 更新档期 ID
        appointment.setAppointmentStatus("pending");  // 状态重置为 pending
        appointment.setRemarks("变更时间");  // 状态重置为 pending
        appointmentMapper.updateById(appointment);

        // 5. 发送邮件通知房东，预约时间已变更
        Landlord landlord = landlordMapper.selectById(appointment.getLandlordId());
        if (landlord != null && landlord.getEmail() != null) {
            changeTimeToLandlord(landlord.getEmail());
        }

        return new Response<>(200, "预约时间变更成功", null);
    }


    // 发送邮件通知房东
    private void changeTimeToLandlord(String landlordEmail) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(senderEmail);  // 发送方邮箱
        message.setTo(landlordEmail);
        message.setSubject("预约时间变更通知");
        message.setText("尊敬的房东，您的房源有预约时间变更，请及时查看预约详情！");

        try {
            mailSender.send(message);
        } catch (Exception e) {
            System.out.println("邮件发送失败：" + e.getMessage());
        }
    }


    /**
     * 取消预约接口
     * @param appointmentId
     * @param userId
     * @return
     */
    @Override
    @Transactional
    public Response<String> cancelAppointment(Long appointmentId, Integer userId) {
        // 1. 查询预约是否存在
        Appointment appointment = appointmentMapper.selectById(appointmentId);
        if (appointment == null) {
            return new Response<>(404, "预约记录不存在", null);
        }

        // 2. 校验用户是否是预约的发起人
        if (!appointment.getUserId().equals(userId)) {
            return new Response<>(403, "您无权取消该预约", null);
        }

        // 3. 更新预约状态为已取消
        appointment.setAppointmentStatus("cancel");
        appointment.setRemarks("已取消");
        int updateCount = appointmentMapper.updateById(appointment);
        if (updateCount <= 0) {
            return new Response<>(500, "取消预约失败", null);
        }

        // 4. 发送邮件通知房东
        Landlord landlord = landlordMapper.selectById(appointment.getLandlordId());
        if (landlord != null && landlord.getEmail() != null) {
            sendCancelEmailToLandlord(landlord.getEmail());
        }

        return new Response<>(200, "预约已取消", null);
    }

    /**
     * 发送邮件通知房东
     */
    private void sendCancelEmailToLandlord(String landlordEmail) {
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(senderEmail);
        message.setTo(landlordEmail);
        message.setSubject("房源预约取消通知");
        message.setText("您好，您的房源预约已被租客取消，请及时查看" );

        try {
            mailSender.send(message);
        } catch (Exception e) {
            System.out.println("邮件发送失败：" + e.getMessage());
        }
    }

}
